package com.ksyun.campus.metaserver.test.integration;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.TestPropertySource;

import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.*;

/**
 * MetaServer 集群集成测试
 * 
 * 注意: 此测试需要预先启动 ZooKeeper 和 MetaServer 集群
 * 运行测试前请执行: bin/start-metaserver-cluster.bat
 */
@SpringBootTest
@TestPropertySource(locations = "classpath:application-test.properties")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ClusterIntegrationTest {
    
    private static final String LEADER_BASE_URL = "http://localhost:8300";
    private static final String FOLLOWER1_BASE_URL = "http://localhost:8301";
    private static final String FOLLOWER2_BASE_URL = "http://localhost:8302";
    
    private final TestRestTemplate restTemplate = new TestRestTemplate();
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    @Test
    @Order(1)
    @DisplayName("测试所有实例健康状态")
    public void testInstancesHealth() throws InterruptedException {
        // 等待实例完全启动
        TimeUnit.SECONDS.sleep(5);
        
        // 测试 Leader 健康状态
        ResponseEntity<String> leaderHealth = restTemplate.getForEntity(
                LEADER_BASE_URL + "/actuator/health", String.class);
        assertEquals(HttpStatus.OK, leaderHealth.getStatusCode());
        
        // 测试 Follower1 健康状态
        ResponseEntity<String> follower1Health = restTemplate.getForEntity(
                FOLLOWER1_BASE_URL + "/actuator/health", String.class);
        assertEquals(HttpStatus.OK, follower1Health.getStatusCode());
        
        // 测试 Follower2 健康状态
        ResponseEntity<String> follower2Health = restTemplate.getForEntity(
                FOLLOWER2_BASE_URL + "/actuator/health", String.class);
        assertEquals(HttpStatus.OK, follower2Health.getStatusCode());
        
        System.out.println("✓ 所有实例健康检查通过");
    }
    
    @Test
    @Order(2)
    @DisplayName("测试集群状态查询")
    public void testClusterStatus() throws Exception {
        ResponseEntity<String> response = restTemplate.getForEntity(
                LEADER_BASE_URL + "/admin/sync/cluster", String.class);
        
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertNotNull(response.getBody());
        
        // 解析响应
        Map<String, Object> result = objectMapper.readValue(response.getBody(), Map.class);
        
        assertTrue(result.containsKey("code"));
        assertEquals(200, result.get("code"));
        
        Map<String, Object> data = (Map<String, Object>) result.get("data");
        assertNotNull(data);
        
        // 验证关键字段
        assertTrue(data.containsKey("currentInstance"));
        assertTrue(data.containsKey("isLeader"));
        assertTrue(data.containsKey("clusterMembers"));
        assertTrue(data.containsKey("isHealthy"));
        
        System.out.println("✓ 集群状态查询测试通过");
        System.out.println("集群信息: " + data);
    }
    
    @Test
    @Order(3)
    @DisplayName("测试同步状态查询")
    public void testSyncStatus() throws Exception {
        ResponseEntity<String> response = restTemplate.getForEntity(
                LEADER_BASE_URL + "/admin/sync/status", String.class);
        
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertNotNull(response.getBody());
        
        // 解析响应
        Map<String, Object> result = objectMapper.readValue(response.getBody(), Map.class);
        
        assertTrue(result.containsKey("code"));
        assertEquals(200, result.get("code"));
        
        Map<String, Object> data = (Map<String, Object>) result.get("data");
        assertNotNull(data);
        
        // 验证关键字段
        assertTrue(data.containsKey("currentInstance"));
        assertTrue(data.containsKey("isLeader"));
        assertTrue(data.containsKey("currentSyncStatus"));
        
        System.out.println("✓ 同步状态查询测试通过");
    }
    
    @Test
    @Order(4)
    @DisplayName("测试同步事件触发")
    public void testSyncEventTrigger() throws Exception {
        ResponseEntity<String> response = restTemplate.postForEntity(
                LEADER_BASE_URL + "/admin/sync/trigger", null, String.class);
        
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertNotNull(response.getBody());
        
        // 解析响应
        Map<String, Object> result = objectMapper.readValue(response.getBody(), Map.class);
        
        assertTrue(result.containsKey("code"));
        assertEquals(200, result.get("code"));
        
        System.out.println("✓ 同步事件触发测试通过");
        
        // 等待同步完成
        TimeUnit.SECONDS.sleep(2);
    }
    
    @Test
    @Order(5)
    @DisplayName("测试基础文件系统操作")
    public void testBasicFileSystemOperations() throws Exception {
        // 创建测试目录
        ResponseEntity<String> mkdirResponse = restTemplate.postForEntity(
                LEADER_BASE_URL + "/mkdir?path=/integration-test&replication=3", 
                null, String.class);
        
        assertEquals(HttpStatus.OK, mkdirResponse.getStatusCode());
        
        // 列出根目录
        ResponseEntity<String> listResponse = restTemplate.getForEntity(
                LEADER_BASE_URL + "/listdir?path=/", String.class);
        
        assertEquals(HttpStatus.OK, listResponse.getStatusCode());
        assertNotNull(listResponse.getBody());
        
        // 验证创建的目录存在
        String listResult = listResponse.getBody();
        assertTrue(listResult.contains("integration-test"));
        
        System.out.println("✓ 基础文件系统操作测试通过");
    }
    
    @Test
    @Order(6)
    @DisplayName("测试 Follower 只读访问")
    public void testFollowerReadOnlyAccess() throws Exception {
        // 从 Follower 读取数据应该成功
        ResponseEntity<String> listResponse = restTemplate.getForEntity(
                FOLLOWER1_BASE_URL + "/listdir?path=/", String.class);
        
        assertEquals(HttpStatus.OK, listResponse.getStatusCode());
        assertNotNull(listResponse.getBody());
        
        // Follower 不应该能执行写操作（如果有相应的检查）
        // 这里可以根据实际实现添加更多测试
        
        System.out.println("✓ Follower 只读访问测试通过");
    }
    
    @Test
    @Order(7)
    @DisplayName("测试同步事件获取")
    public void testSyncEventRetrieval() throws Exception {
        ResponseEntity<String> response = restTemplate.getForEntity(
                LEADER_BASE_URL + "/admin/sync/events?from=0&limit=10", String.class);
        
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertNotNull(response.getBody());
        
        // 解析响应
        Map<String, Object> result = objectMapper.readValue(response.getBody(), Map.class);
        
        assertTrue(result.containsKey("code"));
        assertEquals(200, result.get("code"));
        
        System.out.println("✓ 同步事件获取测试通过");
    }
    
    @Test
    @Order(8)
    @DisplayName("测试非 Leader 实例的管理操作限制")
    public void testNonLeaderManagementRestrictions() throws Exception {
        // Follower 不应该能触发同步
        ResponseEntity<String> response = restTemplate.postForEntity(
                FOLLOWER1_BASE_URL + "/admin/sync/trigger", null, String.class);
        
        // 应该返回错误或重定向到 Leader
        assertTrue(response.getStatusCode() == HttpStatus.BAD_REQUEST || 
                   response.getStatusCode() == HttpStatus.FORBIDDEN ||
                   response.getStatusCode() == HttpStatus.NOT_FOUND);
        
        System.out.println("✓ 非 Leader 管理操作限制测试通过");
    }
    
    @Test
    @Order(9)
    @DisplayName("测试集群完整性")
    public void testClusterIntegrity() throws Exception {
        // 获取集群信息
        ResponseEntity<String> response = restTemplate.getForEntity(
                LEADER_BASE_URL + "/admin/sync/cluster", String.class);
        
        assertEquals(HttpStatus.OK, response.getStatusCode());
        
        Map<String, Object> result = objectMapper.readValue(response.getBody(), Map.class);
        Map<String, Object> data = (Map<String, Object>) result.get("data");
        
        // 验证集群成员数量
        if (data.containsKey("clusterMembers")) {
            Object members = data.get("clusterMembers");
            // 根据实际实现验证成员数量
            assertNotNull(members);
        }
        
        // 验证 Leader 存在
        assertTrue((Boolean) data.get("isLeader"));
        assertTrue((Boolean) data.get("isHealthy"));
        
        System.out.println("✓ 集群完整性测试通过");
        System.out.println("最终集群状态: " + data);
    }
    
    @BeforeAll
    static void setUp() {
        System.out.println("==================================================");
        System.out.println("           MetaServer 集群集成测试");
        System.out.println("==================================================");
        System.out.println("请确保以下服务已启动:");
        System.out.println("  - ZooKeeper (127.0.0.1:2181)");
        System.out.println("  - MetaServer Leader (localhost:8300)");
        System.out.println("  - MetaServer Follower1 (localhost:8301)");
        System.out.println("  - MetaServer Follower2 (localhost:8302)");
        System.out.println("==================================================");
    }
    
    @AfterAll
    static void tearDown() {
        System.out.println("==================================================");
        System.out.println("           集成测试完成");
        System.out.println("==================================================");
        System.out.println("如需停止集群，请执行: bin/stop-metaserver-cluster.bat");
    }
}
